﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using Caliburn.Micro;
using NathansMapInfoProjects.PluginManager.Services;

namespace NathansMapInfoProjects.PluginManager.ViewModels
{
    [Export(typeof(ApplicationsViewModel))]
    public class ApplicationsViewModel : Screen
    {
        readonly UpdateSafeCollection<PluginItem> applications = new UpdateSafeCollection<PluginItem>();
        private bool canrefreshfeeds = true;
        private string status;


        [ImportMany(typeof(IFeedReader))]
        public IEnumerable<IFeedReader> Readers { get; set; }

        [Import(typeof(IEventAggregator))]
        public IEventAggregator EventAggregator { get; set; }

        /// <summary>
        /// List of the currently loaded plugins.
        /// </summary>
        public UpdateSafeCollection<PluginItem> ApplicationsList
        {
            get
            {
                return applications;
            }
        }

        /// <summary>
        /// Gets or sets if the user can refresh the plugin list.
        /// This is normally disabled during fetch operations so that we don't open more connections then needed.
        /// </summary>
        public bool CanRefreshFeeds
        {
            get { return this.canrefreshfeeds; }
            set
            {
                this.canrefreshfeeds = value;
                base.NotifyOfPropertyChange(() => this.CanRefreshFeeds);
            }
        }

        /// <summary>
        /// Shows the current status of the plugin downloading.
        /// </summary>
        public string Status
        {
            get { return this.status; }
            set
            {
                this.status = value;
                base.NotifyOfPropertyChange(() => this.Status);
            }
        }

        /// <summary>
        /// Refreshes the list of plugins in the plugin list.
        /// </summary>
        /// <returns></returns>
        /// <remarks>This method uses the Caluburn.Miro coroutines pattern in order to do asnyc work in one method rather then having event handlers
        /// scattered everywhere.</remarks>
        public IEnumerable<IResult> RefreshFeeds()
        {
            this.Status = "Fecthing plugins...";
            this.CanRefreshFeeds = false;

            yield return new AsAsnyc(
                () =>
                {
                    this.ApplicationsList.Clear();
                    // Loop though each reader and read the plugins.
                    foreach (var feedReader in Readers)
                    {
                        this.Status = "Fetching plugins from " + feedReader.FeedName;

                        if (!feedReader.IsFeedVaild())
                            continue;

                        foreach (var pluginItem in feedReader.GetPlugins())
                        {
                            this.ApplicationsList.Add(pluginItem);
                        }
                    }
                });

            this.Status = string.Empty;
            this.CanRefreshFeeds = true;
        }
    }

    public class ShowScreen : IResult
    {
        readonly Type screen_type;
        readonly string name;

        [Import]
        public IShell Shell { get; set; }

        public ShowScreen(string name)
        {
            this.name = name;
        }

        public ShowScreen(Type screenType)
        {
            this.screen_type = screenType;
        }

        public void Execute(ActionExecutionContext context)
        {
            var screen = !string.IsNullOrEmpty(name)
                ? IoC.Get<object>(name)
                : IoC.GetInstance(screen_type, null);

            Shell.ActivateItem(screen);
            Completed(this, new ResultCompletionEventArgs());
        }

        public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };

        public static ShowScreen Of<T>()
        {
            return new ShowScreen(typeof(T));
        }
    }
}